/**
 * 项目名称（软件名称）：忠旺机械物资管理系统(mms)
 * 研发设计单位：忠旺机械设备制造有限公司机械设计院智能控制设计科设计与研发。
 * 版权所有：忠旺机械设备制造有限公司
 * 注：本项目的一切技术专利，使用规范归解释权由忠旺机械设备制造有限公司所有。
 * 软件版本：Ver 1.0.0
 * 文件路径：com.zhongwang.mms.util
 * 创建时间：2020年05月11日 11时13分
 **/
package com.zhongwang.business.module.system.util;

import com.zhongwang.business.util.ShiroUtils;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URLEncoder;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * @ClassName： XYHFileUtils
 * @Description： 文件处理
 * @Author： 徐一贺
 * @Date： 2020/5/11 11:13
 * @Version： V1.0
 **/
@Log4j2
public class XYHFileUtils {
    /**
     * 文件上传路径
     */
    public static final String BASE_PATH = "e:/business/upload/";

    /**
     * @FunctionName: download
     * @Description: 下载
     * @DesignIdea: 通过设置[HttpServletResponse]返回信息头数据格式进行下载操作
     * @Author: 徐一贺
     * @CreateDate: 2020/5/16 15:52
     * @Phone: 18210416791
     * @Param: [file] 下载文件路径，[fileName]保存的文件名，[HttpServletResponse]  向客户端响应对象
     * @Return: [String] 路径
     * @Throw: 无异常抛出
     * @Version: v 1.0.0
     */
    public static void download(File file, String fileName, HttpServletResponse response) throws IOException {
        try{
            InputStream fis = new BufferedInputStream(new FileInputStream(file.getPath()));
            byte[] buffer = new byte[fis.available()];
            fis.read(buffer);
            fis.close();
            response.reset();
            OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
            response.setContentType("application/octet-stream");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
            toClient.write(buffer);
            toClient.flush();
            toClient.close();
        }catch(Exception e){
            e.printStackTrace();
        }


    }

    /**
     * @FunctionName: upload
     * @Description: 文件上传
     * @DesignIdea: 上传，根据当前年月日生成文件夹，使用uuid生成随机文件名保存文件到指定的文件夹下
     * @Author: 徐一贺
     * @CreateDate: 2020/5/16 15:52
     * @Phone: 18210416791
     * @Param: [file] 文件
     * @Return: [String] 路径
     * @Throw: 无异常抛出
     * @Version: v 1.0.0
     */
    public static String upload(MultipartFile file) throws Exception {
        if (file.isEmpty()) {
            return null;
        }
        String filename = file.getOriginalFilename();

        String ext = null;
        if (filename.contains(".")) {
            ext = filename.substring(filename.lastIndexOf("."));
        } else {
            ext = "";
        }
        String uuid = UUID.randomUUID().toString().replaceAll("-", "");
        String nfileName = uuid + ext;
        String filepath = BASE_PATH;
        File targetFile = new File(filepath, nfileName);
//        if (!targetFile.exists()) {
//            targetFile.mkdirs();
//        } else {
//            targetFile.delete();
//        }
        file.transferTo(targetFile);
        log.debug("上传文件成功 URL：" + filepath);
        return filepath + "/" + nfileName;
    }
    /**
     * @FunctionName: upload
     * @Description: 文件上传
     * @DesignIdea: 上传，根据当前年月日生成文件夹，使用uuid生成随机文件名保存文件到指定的文件夹下
     * @Author: 徐一贺
     * @CreateDate: 2020/5/16 15:52
     * @Phone: 18210416791
     * @Param: [file] 文件
     * @Return: [String] 路径
     * @Throw: 无异常抛出
     * @Version: v 1.0.0
     */
    public static String upload2(MultipartFile file) throws Exception {
        if (file.isEmpty()) {
            return null;
        }
        String filename = file.getOriginalFilename();

        String ext = null;
        if (filename.contains(".")) {
            ext = filename.substring(filename.lastIndexOf("."));
        } else {
            ext = "";
        }
        String uuid = UUID.randomUUID().toString().replaceAll("-", "");
        String nfileName = uuid + ext;
        String dirPath = DateFormatUtils.format(new Date(), "yyyyMMdd");
        String filepath = BASE_PATH.endsWith("/") ? BASE_PATH + dirPath : BASE_PATH + "/" + dirPath;
        File targetFile = new File(filepath, nfileName);
        if (!targetFile.exists()) {
            targetFile.mkdirs();
        } else {
            targetFile.delete();
        }
        file.transferTo(targetFile);
        log.debug("上传文件成功 URL：" + filepath);
        return filepath + "/" + nfileName;
    }

    public final static Map<String, String> FILE_TYPE_MAP = new HashMap<String, String>();

    private XYHFileUtils() {
    }

    static {
        getAllFileType();  //初始化文件类型信息
    }

    /**
     * @FunctionName: getAllFileType
     * @Description: 常见文件头信息
     * @DesignIdea: 初始化魔数码与文件类型的对比，获取上传文件的类型，防木马使用。
     * @Author: 徐一贺
     * @CreateDate: 2020/5/16 15:52
     * @Phone: 18210416791
     * @Param: []
     * @Return: [void]
     * @Throw: 无异常抛出
     * @Version: v 1.0.0
     */
    private static void getAllFileType() {
        FILE_TYPE_MAP.put("jpg", "FFD8FF"); //JPEG (jpg)
        FILE_TYPE_MAP.put("exe", "4D5A"); //可执行文件 (exe)
        FILE_TYPE_MAP.put("png", "89504E47");  //PNG (png)
        FILE_TYPE_MAP.put("gif", "47494638");  //GIF (gif)
        FILE_TYPE_MAP.put("tif", "49492A00");  //TIFF (tif)
        FILE_TYPE_MAP.put("bmp", "424D"); //Windows Bitmap (bmp)
        FILE_TYPE_MAP.put("dwg", "41433130"); //CAD (dwg)
        FILE_TYPE_MAP.put("html", "68746D6C3E");  //HTML (html)
        FILE_TYPE_MAP.put("rtf", "7B5C727466");  //Rich Text Format (rtf)
        FILE_TYPE_MAP.put("xml", "3C3F786D6C");
        FILE_TYPE_MAP.put("zip", "504B0304");
        FILE_TYPE_MAP.put("rar", "52617221");
        FILE_TYPE_MAP.put("psd", "38425053");  //Photoshop (psd)
        FILE_TYPE_MAP.put("eml", "44656C69766572792D646174653A");  //Email [thorough only] (eml)
        FILE_TYPE_MAP.put("dbx", "CFAD12FEC5FD746F");  //Outlook Express (dbx)
        FILE_TYPE_MAP.put("pst", "2142444E");  //Outlook (pst)
        FILE_TYPE_MAP.put("xls", "D0CF11E0");  //MS Word
        FILE_TYPE_MAP.put("doc", "D0CF11E0");  //MS Excel 注意：word 和 excel的文件头一样
        FILE_TYPE_MAP.put("mdb", "5374616E64617264204A");  //MS Access (mdb)
        FILE_TYPE_MAP.put("wpd", "FF575043"); //WordPerfect (wpd)
        FILE_TYPE_MAP.put("eps", "252150532D41646F6265");
        FILE_TYPE_MAP.put("ps", "252150532D41646F6265");
        FILE_TYPE_MAP.put("pdf", "255044462D312E");  //Adobe Acrobat (pdf)
        FILE_TYPE_MAP.put("qdf", "AC9EBD8F");  //Quicken (qdf)
        FILE_TYPE_MAP.put("pwl", "E3828596");  //Windows Password (pwl)
        FILE_TYPE_MAP.put("wav", "57415645");  //Wave (wav)
        FILE_TYPE_MAP.put("avi", "41564920");
        FILE_TYPE_MAP.put("ram", "2E7261FD");  //Real Audio (ram)
        FILE_TYPE_MAP.put("rm", "2E524D46");  //Real Media (rm)
        FILE_TYPE_MAP.put("mpg", "000001BA");  //
        FILE_TYPE_MAP.put("mov", "6D6F6F76");  //Quicktime (mov)
        FILE_TYPE_MAP.put("asf", "3026B2758E66CF11"); //Windows Media (asf)
        FILE_TYPE_MAP.put("mid", "4D546864");  //MIDI (mid)
    }


    /**
     * @FunctionName: getImageFileType
     * @Description: 获取图片文件实际类型
     * @DesignIdea: 获取图片文件实际类型, 若不是图片则返回null
     * @Author: 徐一贺
     * @CreateDate: 2020/5/16 15:52
     * @Phone: 18210416791
     * @Param: [f] 文件
     * @Return: [String] 文件类型
     * @Throw: 无异常抛出
     * @Version: v 1.0.0
     */
    public final static String getImageFileType(File f) {
        if (isImage(f)) {
            try {
                ImageInputStream iis = ImageIO.createImageInputStream(f);
                Iterator<ImageReader> iter = ImageIO.getImageReaders(iis);
                if (!iter.hasNext()) {
                    return null;
                }
                ImageReader reader = iter.next();
                iis.close();
                return reader.getFormatName();
            } catch (IOException e) {
                return null;
            } catch (Exception e) {
                return null;
            }
        }
        return null;
    }

    /**
     * @FunctionName: getFileByFile
     * @Description: 获取文件类型
     * @DesignIdea: 获取文件类型, 包括图片, 若格式不是已配置的, 则返回null
     * @Author: 徐一贺
     * @CreateDate: 2020/5/16 15:52
     * @Phone: 18210416791
     * @Param: [file] 文件
     * @Return: [String] 文件类型
     * @Throw: 无异常抛出
     * @Version: v 1.0.0
     */
    public final static String getFileByFile(File file) {
        String filetype = null;
        byte[] b = new byte[50];
        try {
            InputStream is = new FileInputStream(file);
            is.read(b);
            filetype = getFileTypeByStream(b);
            is.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return filetype;
    }

    /**
     * @FunctionName: getFileTypeByStream
     * @Description: 文件流中获取文件类型
     * @DesignIdea: 文件流中获取文件类型, 若格式不是已配置的, 则返回null
     * @Author: 徐一贺
     * @CreateDate: 2020/5/16 15:52
     * @Phone: 18210416791
     * @Param: [b] 文件流
     * @Return: [String] 文件类型
     * @Throw: 无异常抛出
     * @Version: v 1.0.0
     */
    public final static String getFileTypeByStream(byte[] b) {
        String filetypeHex = String.valueOf(getFileHexString(b));
        Iterator<Map.Entry<String, String>> entryiterator = FILE_TYPE_MAP.entrySet().iterator();
        while (entryiterator.hasNext()) {
            Map.Entry<String, String> entry = entryiterator.next();
            String fileTypeHexValue = entry.getValue();
            if (filetypeHex.toUpperCase().startsWith(fileTypeHexValue)) {
                return entry.getKey();
            }
        }
        return null;
    }

    /**
     * @FunctionName: isImage
     * @Description: 判断文件是否为图片
     * @DesignIdea: 判断文件是否为图片
     * @Author: 徐一贺
     * @CreateDate: 2020/5/16 15:52
     * @Phone: 18210416791
     * @Param: [file] 文件
     * @Return: [boolean] 判断结果
     * @Throw: 无异常抛出
     * @Version: v 1.0.0
     */
    public static final boolean isImage(File file) {
        boolean flag = false;
        try {
            BufferedImage bufreader = ImageIO.read(file);
            int width = bufreader.getWidth();
            int height = bufreader.getHeight();
            if (width == 0 || height == 0) {
                flag = false;
            } else {
                flag = true;
            }
        } catch (IOException e) {
            flag = false;
        } catch (Exception e) {
            flag = false;
        }
        return flag;
    }

    /**
     * @FunctionName: getFileHexString
     * @Description: 文件流中获取魔数码
     * @DesignIdea: 文件流中获取文件类型 16进制码位置，格式化魔数码并返回。
     * @Author: 徐一贺
     * @CreateDate: 2020/5/16 15:52
     * @Phone: 18210416791
     * @Param: [b] 文件流
     * @Return: [String] 魔数码
     * @Throw: 无异常抛出
     * @Version: v 1.0.0
     */
    public final static String getFileHexString(byte[] b) {
        StringBuilder stringBuilder = new StringBuilder();
        if (b == null || b.length <= 0) {
            return null;
        }
        for (int i = 0; i < b.length; i++) {
            int v = b[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }



    /**
     *
     * @param files List<File> 作为参数传进来，就是把多个文件的路径放到一个list里面
     * @param response
     * @return
     * @throws Exception
     */
    public static HttpServletResponse downLoadFiles(List<File> files, HttpServletResponse response) throws Exception {

        try {
            // 临时文件夹 最好是放在服务器上，方法最后有删除临时文件的步骤

            String zipFolderPath = "E:/business/"+ ShiroUtils.getUser().getAccount();
            File folderFile = new File(zipFolderPath);
            if(!folderFile.exists()){//如果文件夹不存在
                folderFile.mkdir();//创建文件夹
            }
            String zipFilename = "E:/business/"+ShiroUtils.getUser().getAccount()+"/tempFile.zip";
            File file = new File(zipFilename);
            file.createNewFile();
            if (!file.exists()) {
                file.createNewFile();
            }
            response.reset();
            // response.getWriter()
            // 创建文件输出流
            FileOutputStream fous = new FileOutputStream(file);
            ZipOutputStream zipOut = new ZipOutputStream(fous);
            zipFile(files, zipOut);
            zipOut.close();
            fous.close();
            return downloadZip(file, response);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return response;
    }

    /**
     * 把接受的全部文件打成压缩包
     *
     * @param files<File>;
     * @param outputStream
     */
    public static void zipFile(List files, ZipOutputStream outputStream) {
        int size = files.size();
        for (int i = 0; i < size; i++) {
            File file = (File) files.get(i);
            zipFile(file, outputStream);
        }
    }

    /**
     * 根据输入的文件与输出流对文件进行打包
     *
     * @param inputFile
     * @param ouputStream
     */
    public static void zipFile(File inputFile, ZipOutputStream ouputStream) {
        try {
            if (inputFile.exists()) {
                if (inputFile.isFile()) {
                    FileInputStream IN = new FileInputStream(inputFile);
                    BufferedInputStream bins = new BufferedInputStream(IN, 512);
                    ZipEntry entry = new ZipEntry(inputFile.getName());
                    ouputStream.putNextEntry(entry);
                    // 向压缩文件中输出数据
                    int nNumber;
                    byte[] buffer = new byte[512];
                    while ((nNumber = bins.read(buffer)) != -1) {
                        ouputStream.write(buffer, 0, nNumber);
                    }
                    // 关闭创建的流对象
                    bins.close();
                    IN.close();
                } else {
                    try {
                        File[] files = inputFile.listFiles();
                        for (int i = 0; i < files.length; i++) {
                            zipFile(files[i], ouputStream);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static HttpServletResponse downloadZip(File file, HttpServletResponse response) {
        if (file.exists() == false) {
            System.out.println("待压缩的文件目录：" + file + "不存在.");
        } else {
            try {
                // 以流的形式下载文件。
                InputStream fis = new BufferedInputStream(new FileInputStream(file.getPath()));
                byte[] buffer = new byte[fis.available()];
                fis.read(buffer);
                fis.close();
                // 清空response
                response.reset();

                OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
                response.setContentType("application/octet-stream");

                // 如果输出的是中文名的文件，在此处就要用URLEncoder.encode方法进行处理
                response.setHeader("Content-Disposition",
                        "attachment;filename=" + new String(file.getName().getBytes("GB2312"), "ISO8859-1"));
                toClient.write(buffer);
                toClient.flush();
                toClient.close();
            } catch (Exception ex) {
                ex.printStackTrace();
            } finally {
                try {
                    File f = new File(file.getPath());
                    f.delete();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return response;
    }
}